Tasks
- (10 pts / 1 hr) Install MySQL using the instructions provided in the practicum.

- (10 pts / 2 hrs) Create an R or Jupyter Notebook.

- (10 pts / 2 hrs) Analyze the problem of contact tracing and create a conceptual model in UML.

- (10 pts / 1 hr) From the Conceptual Model, construct a logical data model expressed as an ERD using IE (Crow’s Foot) and a tool of your choice that is in at least BCNF.

- Using functional dependencies, show that the schema in in at least BCNF
[Person]
PersonId: single valued
EmployeeId: single valued
FirstName: single valued
LastName: single valued
DOB: single valued
Gender: single valued
Address: single valued
City: single valued
State: single valued
Phone: single valued
Email: single valued
SMS: single valued
DateOfStartQuarantine: single valued
1NF ✔️
(key)A: PersonId
(non-key)B: EmployeeId
(non-key)C: FirstName
(non-key)D: LastName
(non-key)E: DOB
(non-key)F: Gender
(non-key)G: Address
(non-key)H: City
(non-key)I: State
(non-key)J: Phone
(non-key)K: Email
(non-key)L: SMS
(non-key)M: DateOfStartQuarantine
A -> B
A -> C
A -> D
A -> E
A -> F
A -> G
A -> H
A -> I
A -> J
A -> K
A -> L
A -> M
2NF ✔️
No non-key attribute can decide A(key), so BCNF ✔️
[MedicalProvider]
MedicalProviderId: single valued
Title: single valued
FirstName: single valued
LastName: single valued
PersonId: single valued
1NF ✔️
(key)A: MedicalProviderId
(non-key)B: Title
(non-key)C: FirstName
(non-key)D: LastName
(non-key)E: PersonId
A -> B
A -> C
A -> D
A -> E
2NF ✔️
No non-key attribute can decide A(key), so BCNF ✔️
[Hospital]
HospitalId: single valued
Name: single valued
Address: single valued
Phone: single valued
1NF ✔️
(key)A: HospitalId
(non-key)B: Name
(non-key)C: Address
(non-key)D: Phone
A -> B
A -> C
A -> D
2NF ✔️
No non-key attribute can decide A(key), so BCNF ✔️
[Symptom]
SymptomId: single valued
ReportId: single valued
DateOfSymptomOnset: single valued
SymptomDetail: single valued
1NF ✔️
(key)A: SymptomId
(non-key)B: ReportId
(non-key)C: DateOfSymptomOnset
(non-key)D: SymptomDetail
A -> B
A -> C
A -> D
2NF ✔️
No non-key attribute can decide A(key), so BCNF ✔️
[SelfReport]
ReportId: single valued
PersonId: single valued
ReportDate: single valued
Detail: single valued
Temperature: single valued
ProtectiveBehavior: single valued
Quarantined: single valued
1NF ✔️
(key)A: ReportId
(non-key)B: PersonId
(non-key)C: ReportDate
(non-key)D: Detail
(non-key)E: Temperature
(non-key)F: ProtectiveBehavior
(non-key)G: Quarantined
A -> B
A -> C
A -> D
A -> E
A -> F
A -> G
2NF ✔️
No non-key attribute can decide A(key), so BCNF ✔️
[TestResult]
TestResultId: single valued
ReportId: single valued
Description: single valued
Positive: single valued
(key)A: TestResultId
(non-key)B: ReportId
(non-key)C: Description
(non-key)D: Positive
A -> B
A -> C
A -> D
2NF ✔️
No non-key attribute can decide A(key), so BCNF ✔️
[Employee]
EmployeeId: single valued
FirstName: single valued
LastName: single valued
Phone: single valued
1NF ✔️
(key)A: EmployeeId
(non-key)B: FirstName
(non-key)C: LastName
(non-key)D: Phone
A -> B
A -> C
A -> D
2NF ✔️
No non-key attribute can decide A(key), so BCNF ✔️
[Event]
EventId: single valued
EventDate: single valued
Address: single valued
City: single valued
State: single valued
Detail: single valued
1NF ✔️
(key)A: EventId
(non-key)B: EventDate
(non-key)C: Address
(non-key)D: City
(non-key)E: State
(non-key)F: Detail
A -> B
A -> C
A -> D
A -> E
A -> F
2NF ✔️
No non-key attribute can decide A(key), so BCNF ✔️
[SupportiveServices]
SupportiveServicesId: single valued
Title: single valued
PersonId: single valued
1NF ✔️
(key)A: SupportiveServicesId
(non-key)B: Title
(non-key)C: PersonId
A -> B
A -> C
2NF ✔️
No non-key attribute can decide A(key), so BCNF ✔️
[Notification]
NotificationId: single valued
PersonId: single valued
NotificationType: single valued
NotificationDate: single valued
Detail: single valued
1NF ✔️
(key)A: NotificationId
(non-key)B: PersonId
(non-key)C: NotificationType
(non-key)D: NotificationDate
(non-key)E: Detail
A -> B
A -> C
A -> D
A -> E
2NF ✔️
No non-key attribute can decide A(key), so BCNF ✔️
- (20 pts / 1.5 hrs) Create a set of SQL data definition statements, realize that schema in MySQL by executing the script from the MySQL console.
CREATE TABLE Hospital (
HospitalId INT NOT NULL,
Name VARCHAR(45),
Address VARCHAR(45),
Phone VARCHAR(20),
PRIMARY KEY (HospitalId)
)
COMMENT = 'Health center for connecting with patients and contacts.';
CREATE TABLE MedicalProvider (
MedicalProviderId INT NOT NULL,
Title VARCHAR(20),
FirstName VARCHAR(20),
LastName VARCHAR(20),
HospitalId INT NOT NULL,
PRIMARY KEY (MedicalProviderId),
FOREIGN KEY (HospitalId)
REFERENCES Hospital(HospitalId)
)
COMMENT = 'Doctor who diagnosis patients.';
CREATE TABLE Employee (
EmployeeId INT NOT NULL,
FirstName VARCHAR(20),
LastName VARCHAR(20),
Phone INT,
PRIMARY KEY (EmployeeId)
)
COMMENT = 'Employee from health department who is responsible for contacting patients and contact.';
CREATE TABLE Person (
PersonId INT NOT NULL,
MedicalProviderId INT,
EmployeeId INT NOT NULL,
FirstName VARCHAR(20),
LastName VARCHAR(20),
DOB DATE,
Gender ENUM('male', 'female'),
Address VARCHAR(45),
City VARCHAR(45),
State VARCHAR(45),
Phone VARCHAR(45),
Email VARCHAR(45),
SMS VARCHAR(45),
DateOfStartQuarantine DATE,
SourceOfInfection VARCHAR(45),
RiskLevel INT,
PRIMARY KEY (PersonId),
FOREIGN KEY (MedicalProviderId)
REFERENCES MedicalProvider(MedicalProviderId),
FOREIGN KEY (EmployeeId)
REFERENCES Employee(EmployeeId)
)
COMMENT = 'Either a test positive patient or a potiential patient who contacts with a patient';
CREATE TABLE Notification (
NotificationId INT NOT NULL,
PersonId INT NOT NULL,
NotificationType VARCHAR(45),
NotificationDate DATE,
Detail VARCHAR(45),
PRIMARY KEY (NotificationId),
FOREIGN KEY (PersonId)
REFERENCES Person (PersonId)
)
COMMENT = 'Both patients and contacts will receive notification based on their health condition.';
CREATE TABLE Event (
EventId INT NOT NULL,
EventDate DATE,
Address VARCHAR(45),
City VARCHAR(45),
State VARCHAR(45),
Detail VARCHAR(45),
PRIMARY KEY (EventId)
)
COMMENT = 'The event that patients and contacts attend.';
CREATE TABLE PersonEvent (
PersonId INT NOT NULL,
EventId INT NOT NULL,
PRIMARY KEY (PersonId, EventId),
FOREIGN KEY (PersonId)
REFERENCES Person(PersonId),
FOREIGN KEY (EventId)
REFERENCES Event(EventId)
);
CREATE TABLE SupportiveServices (
SupportiveServicesId INT NOT NULL,
Title VARCHAR(45),
PRIMARY KEY (SupportiveServicesId)
)
COMMENT = 'Both patients and contacts will get support services during their quarantine if they face any inconvenience.';
CREATE TABLE ServicesPerson (
SupportiveServicesId INT NOT NULL,
PersonId INT NOT NULL,
PRIMARY KEY (SupportiveServicesId, PersonId),
FOREIGN KEY (SupportiveServicesId)
REFERENCES SupportiveServices(SupportiveServicesId),
FOREIGN KEY (PersonId)
REFERENCES Person(PersonId)
);
CREATE TABLE SelfReport (
ReportId INT NOT NULL,
PersonId INT NOT NULL,
ReportDate DATE,
Temperature INT,
ProtectiveBehavior VARCHAR(45),
Quarantined TINYINT,
PRIMARY KEY (ReportId),
FOREIGN KEY (PersonId)
REFERENCES Person(PersonId)
)
COMMENT = 'Daily data report such as temperature data, contact data.';
CREATE TABLE TestResult (
TestResultId INT NOT NULL,
ReportId INT NOT NULL,
Description VARCHAR(45),
Positive TINYINT,
PRIMARY KEY (TestResultId),
FOREIGN KEY (ReportId)
REFERENCES SelfReport(ReportId)
)
COMMENT = 'If the test result is positive, which means this patient / contacts is diagnosed with Covid-19.';
CREATE TABLE Symptom (
SymptomId INT NOT NULL,
ReportId INT NOT NULL,
DateOfSymptomOnset DATE,
SymptomDetail VARCHAR(45),
PRIMARY KEY (SymptomId),
FOREIGN KEY (ReportId)
REFERENCES SelfReport(ReportId)
)
COMMENT = 'Symptom description.';
- Table [Employee] successfully created

- Table [Event] successfully created

- Table [Hospital] successfully created

- Table [MedicalProvider] successfully created

- Table [Notification] successfully created

- Table [Person] successfully created

- Table [PersonEvent] successfully created

- Table [SelfReport] successfully created

- Table [ServicesPerson] successfully created

- Table [SupportiveServices] successfully created

- Table [Symptom] successfully created

- Table [TestResult] successfully created

- (20 pts / 2 hrs) Work as a group to populate the tables with test data.












- (20 pts / 1 hrs) Define and execute at least five queries that demonstrate that your database is working.
-- Query 1: find the names and addresses of hospital which have more than 5 person and how much persons they have.
-- a join of at least three tables
-- a group by with a having clause
SELECT
h.Name,
h.Address,
COUNT(p.PersonId) personCount
FROM Hospital h
JOIN MedicalProvider m
ON m.HospitalId=h.HospitalId
JOIN Person p
ON p.MedicalProviderId=m.MedicalProviderId
GROUP BY h.name
HAVING personCount>5;
-- Query 2: find the numbers of male and female persons.
-- an advanced query mechanisms SELECT CASE/WHEN
SELECT
SUM(CASE WHEN Gender='male' THEN 1 ELSE 0 END) maleCount,
SUM(CASE WHEN Gender='female' THEN 1 ELSE 0 END) femaleCount
FROM Person;
-- Query 3: find the reports starting from April 2020 which have symptom but test negative, ordering by latest date
-- a subquery
-- a complex search criterion using AND
SELECT *
FROM SelfReport r
WHERE r.ReportDate >= '2020-04-01'
AND EXISTS (SELECT 1 FROM Symptom s WHERE s.ReportId=r.ReportId)
AND r.ReportId NOT IN (SELECT ReportId FROM TestResult WHERE Positive=True)
ORDER BY r.ReportDate DESC;
-- Query 4: find the age range distribution of persons.
-- an advanced query mechanisms SELECT CASE/WHEN
SELECT
CASE WHEN (DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(DOB, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(DOB, '00-%m-%d'))) < 20 THEN '<20'
WHEN (DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(DOB, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(DOB, '00-%m-%d'))) < 30 THEN '20-29'
WHEN (DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(DOB, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(DOB, '00-%m-%d'))) < 40 THEN '30-39'
WHEN (DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(DOB, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(DOB, '00-%m-%d'))) < 50 THEN '40-49'
WHEN (DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(DOB, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(DOB, '00-%m-%d'))) < 60 THEN '50-59'
ELSE '>60' END AS age,
COUNT(PersonId) persons
FROM Person
GROUP BY age
ORDER BY FIELD(age, '<20', '20-29', '30-39', '40-49', '50-59', '>60');
-- Query 5:Find the names attend Music event.
-- join of at least 3 tables.
-- contain a complex search criterion using LIKE.
SELECT distinct Person.FirstName, Person.LastName
FROM Person
JOIN PersonEvent ON PersonEvent.PersonId = Person.PersonId
JOIN Event ON Event.EventId = PersonEvent.EventId
WHERE Event.Detail LIKE "%Music%";
-- Query 6: Find the number of Male who tests positive.
-- join of at least 3 tables.
-- contain a complex search criterion using AND.
SELECT COUNT(*) AS Number
FROM Person
JOIN SelfReport ON SelfReport.PersonId = Person.PersonId
JOIN TestResult ON TestResult.ReportId = SelfReport.ReportId
WHERE TestResult.Positive = 'True'
AND Person.Gender = 'Male';
-- Query 7: List the Service name and the number of that Service, which is greater than 2.
-- group by with a having clause
SELECT SupportiveServices.Title, COUNT(ServicesPerson.SupportiveServicesId) AS Number
FROM ServicesPerson
JOIN SupportiveServices ON ServicesPerson.SupportiveServicesId = SupportiveServices.SupportiveServicesId
GROUP BY ServicesPerson.SupportiveServicesId
HAVING Number >2;
Query 1: 
Query 2: 
Query 3: 
Query 4: 
Query 5: 
Query 6: 
Query 7: 
# load libraries
library(DBI)
library(odbc)
library(ggplot2)
# connect to mysql
con <- DBI::dbConnect(odbc::odbc(),
Driver = "MySQL",
Server = "cs5200.cerugoc9p5ux.us-east-1.rds.amazonaws.com",
Database = "practicum-i",
UID = "admin",
PWD = "cs5200db",
Port = 3306)
# build query
query <- dbSendQuery(con, "SELECT
CASE WHEN (DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(DOB, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(DOB, '00-%m-%d'))) < 20 THEN '<20'
WHEN (DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(DOB, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(DOB, '00-%m-%d'))) < 30 THEN '20-29'
WHEN (DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(DOB, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(DOB, '00-%m-%d'))) < 40 THEN '30-39'
WHEN (DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(DOB, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(DOB, '00-%m-%d'))) < 50 THEN '40-49'
WHEN (DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(DOB, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(DOB, '00-%m-%d'))) < 60 THEN '50-59'
ELSE '>60' END AS age,
COUNT(PersonId) persons
FROM Person
GROUP BY age
ORDER BY FIELD(age, '<20', '20-29', '30-39', '40-49', '50-59', '>60')")
# fetch data
df <- dbFetch(query)
# lock the order
df$age <- factor(df$age, levels = df$age)
# plot
ggplot(df, aes(x=age, y=persons)) +
geom_col(data=df) +
scale_y_continuous(limits=c(0,20))

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKIyMjIEF1dGhvcnM6Ci0gU2ltaW4gWmhhbmcKLSBZaW1hbiBMaXUKLSBaaGkgV2VuCgojIFRhc2tzCjEuICgxMCBwdHMgLyAxIGhyKSBJbnN0YWxsIE15U1FMIHVzaW5nIHRoZSBpbnN0cnVjdGlvbnMgcHJvdmlkZWQgaW4gdGhlIHByYWN0aWN1bS4KCjxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20veWltYW5saXUwL2RhdGFiYXNlL21hc3Rlci9pbWFnZS9teVNRTC5wbmciPgoKMi4gKDEwIHB0cyAvIDIgaHJzKSBDcmVhdGUgYW4gUiBvciBKdXB5dGVyIE5vdGVib29rLgoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlL1JOb3RlYm9vay5wbmciPgoKCjMuICgxMCBwdHMgLyAyIGhycykgQW5hbHl6ZSB0aGUgcHJvYmxlbSBvZiBjb250YWN0IHRyYWNpbmcgYW5kIGNyZWF0ZSBhIGNvbmNlcHR1YWwgbW9kZWwgaW4gVU1MLgoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlL1VNTC5wbmciPgoKNC4gKDEwIHB0cyAvIDEgaHIpIEZyb20gdGhlIENvbmNlcHR1YWwgTW9kZWwsIGNvbnN0cnVjdCBhIGxvZ2ljYWwgZGF0YSBtb2RlbCBleHByZXNzZWQgYXMgYW4gRVJEIHVzaW5nIElFIChDcm93J3MgRm9vdCkgYW5kIGEgdG9vbCBvZiB5b3VyIGNob2ljZSB0aGF0IGlzIGluIGF0IGxlYXN0IEJDTkYuIAoKLSBFUkQgJiBVUkwgdG8gaXRzIEx1Y2lkQ2hhcnQgZGlhZ3JhbTogaHR0cHM6Ly9sdWNpZC5hcHAvbHVjaWRjaGFydC82MTRmMjgwZS1mNmQ2LTRhODctYmQ4Mi1lOWIzYTFmOGYxNjEvZWRpdD9wYWdlPTBfMCM/Zm9sZGVyX2lkPWhvbWUmYnJvd3Nlcj1pY29uCgo8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3lpbWFubGl1MC9kYXRhYmFzZS9tYXN0ZXIvaW1hZ2UvRVJELnBuZyI+CgotIFVzaW5nIGZ1bmN0aW9uYWwgZGVwZW5kZW5jaWVzLCBzaG93IHRoYXQgdGhlIHNjaGVtYSBpbiBpbiBhdCBsZWFzdCBCQ05GCgpgYGAKW1BlcnNvbl0KClBlcnNvbklkOiBzaW5nbGUgdmFsdWVkCkVtcGxveWVlSWQ6IHNpbmdsZSB2YWx1ZWQKRmlyc3ROYW1lOiBzaW5nbGUgdmFsdWVkCkxhc3ROYW1lOiBzaW5nbGUgdmFsdWVkCkRPQjogc2luZ2xlIHZhbHVlZApHZW5kZXI6IHNpbmdsZSB2YWx1ZWQKQWRkcmVzczogc2luZ2xlIHZhbHVlZApDaXR5OiBzaW5nbGUgdmFsdWVkClN0YXRlOiBzaW5nbGUgdmFsdWVkClBob25lOiBzaW5nbGUgdmFsdWVkCkVtYWlsOiBzaW5nbGUgdmFsdWVkClNNUzogc2luZ2xlIHZhbHVlZApEYXRlT2ZTdGFydFF1YXJhbnRpbmU6IHNpbmdsZSB2YWx1ZWQKMU5GIOKclO+4jwoKKGtleSlBOiBQZXJzb25JZAoobm9uLWtleSlCOiBFbXBsb3llZUlkCihub24ta2V5KUM6IEZpcnN0TmFtZQoobm9uLWtleSlEOiBMYXN0TmFtZQoobm9uLWtleSlFOiBET0IKKG5vbi1rZXkpRjogR2VuZGVyCihub24ta2V5KUc6IEFkZHJlc3MKKG5vbi1rZXkpSDogQ2l0eQoobm9uLWtleSlJOiBTdGF0ZQoobm9uLWtleSlKOiBQaG9uZQoobm9uLWtleSlLOiBFbWFpbAoobm9uLWtleSlMOiBTTVMKKG5vbi1rZXkpTTogRGF0ZU9mU3RhcnRRdWFyYW50aW5lCgpBIC0+IEIKQSAtPiBDCkEgLT4gRApBIC0+IEUKQSAtPiBGCkEgLT4gRwpBIC0+IEgKQSAtPiBJCkEgLT4gSgpBIC0+IEsKQSAtPiBMCkEgLT4gTQoyTkYg4pyU77iPCgpObyBub24ta2V5IGF0dHJpYnV0ZSBjYW4gZGVjaWRlIEEoa2V5KSwgc28gQkNORiDinJTvuI8KCltNZWRpY2FsUHJvdmlkZXJdCgpNZWRpY2FsUHJvdmlkZXJJZDogc2luZ2xlIHZhbHVlZApUaXRsZTogc2luZ2xlIHZhbHVlZApGaXJzdE5hbWU6IHNpbmdsZSB2YWx1ZWQKTGFzdE5hbWU6IHNpbmdsZSB2YWx1ZWQKUGVyc29uSWQ6IHNpbmdsZSB2YWx1ZWQKMU5GIOKclO+4jwoKKGtleSlBOiBNZWRpY2FsUHJvdmlkZXJJZAoobm9uLWtleSlCOiBUaXRsZQoobm9uLWtleSlDOiBGaXJzdE5hbWUKKG5vbi1rZXkpRDogTGFzdE5hbWUKKG5vbi1rZXkpRTogUGVyc29uSWQKCkEgLT4gQgpBIC0+IEMKQSAtPiBECkEgLT4gRQoyTkYg4pyU77iPCgpObyBub24ta2V5IGF0dHJpYnV0ZSBjYW4gZGVjaWRlIEEoa2V5KSwgc28gQkNORiDinJTvuI8KCltIb3NwaXRhbF0KCkhvc3BpdGFsSWQ6IHNpbmdsZSB2YWx1ZWQKTmFtZTogc2luZ2xlIHZhbHVlZApBZGRyZXNzOiBzaW5nbGUgdmFsdWVkClBob25lOiBzaW5nbGUgdmFsdWVkCjFORiDinJTvuI8KCihrZXkpQTogSG9zcGl0YWxJZAoobm9uLWtleSlCOiBOYW1lCihub24ta2V5KUM6IEFkZHJlc3MKKG5vbi1rZXkpRDogUGhvbmUKCkEgLT4gQgpBIC0+IEMKQSAtPiBECjJORiDinJTvuI8KCk5vIG5vbi1rZXkgYXR0cmlidXRlIGNhbiBkZWNpZGUgQShrZXkpLCBzbyBCQ05GIOKclO+4jwoKW1N5bXB0b21dCgpTeW1wdG9tSWQ6IHNpbmdsZSB2YWx1ZWQKUmVwb3J0SWQ6IHNpbmdsZSB2YWx1ZWQKRGF0ZU9mU3ltcHRvbU9uc2V0OiBzaW5nbGUgdmFsdWVkClN5bXB0b21EZXRhaWw6IHNpbmdsZSB2YWx1ZWQKMU5GIOKclO+4jwoKKGtleSlBOiBTeW1wdG9tSWQKKG5vbi1rZXkpQjogUmVwb3J0SWQKKG5vbi1rZXkpQzogRGF0ZU9mU3ltcHRvbU9uc2V0Cihub24ta2V5KUQ6IFN5bXB0b21EZXRhaWwKCkEgLT4gQgpBIC0+IEMKQSAtPiBECjJORiDinJTvuI8KCk5vIG5vbi1rZXkgYXR0cmlidXRlIGNhbiBkZWNpZGUgQShrZXkpLCBzbyBCQ05GIOKclO+4jwoKW1NlbGZSZXBvcnRdCgpSZXBvcnRJZDogc2luZ2xlIHZhbHVlZApQZXJzb25JZDogc2luZ2xlIHZhbHVlZApSZXBvcnREYXRlOiAgc2luZ2xlIHZhbHVlZApEZXRhaWw6IHNpbmdsZSB2YWx1ZWQKVGVtcGVyYXR1cmU6IHNpbmdsZSB2YWx1ZWQKUHJvdGVjdGl2ZUJlaGF2aW9yOiBzaW5nbGUgdmFsdWVkClF1YXJhbnRpbmVkOiBzaW5nbGUgdmFsdWVkCjFORiDinJTvuI8KCihrZXkpQTogUmVwb3J0SWQKKG5vbi1rZXkpQjogUGVyc29uSWQKKG5vbi1rZXkpQzogUmVwb3J0RGF0ZQoobm9uLWtleSlEOiBEZXRhaWwKKG5vbi1rZXkpRTogVGVtcGVyYXR1cmUKKG5vbi1rZXkpRjogUHJvdGVjdGl2ZUJlaGF2aW9yCihub24ta2V5KUc6IFF1YXJhbnRpbmVkCgpBIC0+IEIKQSAtPiBDCkEgLT4gRApBIC0+IEUKQSAtPiBGCkEgLT4gRwoyTkYg4pyU77iPCgpObyBub24ta2V5IGF0dHJpYnV0ZSBjYW4gZGVjaWRlIEEoa2V5KSwgc28gQkNORiDinJTvuI8KCltUZXN0UmVzdWx0XQoKVGVzdFJlc3VsdElkOiBzaW5nbGUgdmFsdWVkClJlcG9ydElkOiBzaW5nbGUgdmFsdWVkCkRlc2NyaXB0aW9uOiBzaW5nbGUgdmFsdWVkClBvc2l0aXZlOiBzaW5nbGUgdmFsdWVkCgooa2V5KUE6IFRlc3RSZXN1bHRJZAoobm9uLWtleSlCOiBSZXBvcnRJZAoobm9uLWtleSlDOiBEZXNjcmlwdGlvbgoobm9uLWtleSlEOiBQb3NpdGl2ZQoKQSAtPiBCCkEgLT4gQwpBIC0+IEQKMk5GIOKclO+4jwoKTm8gbm9uLWtleSBhdHRyaWJ1dGUgY2FuIGRlY2lkZSBBKGtleSksIHNvIEJDTkYg4pyU77iPCgpbRW1wbG95ZWVdCgpFbXBsb3llZUlkOiBzaW5nbGUgdmFsdWVkCkZpcnN0TmFtZTogc2luZ2xlIHZhbHVlZApMYXN0TmFtZTogc2luZ2xlIHZhbHVlZApQaG9uZTogc2luZ2xlIHZhbHVlZAoxTkYg4pyU77iPCgooa2V5KUE6IEVtcGxveWVlSWQKKG5vbi1rZXkpQjogRmlyc3ROYW1lCihub24ta2V5KUM6IExhc3ROYW1lCihub24ta2V5KUQ6IFBob25lCgpBIC0+IEIKQSAtPiBDCkEgLT4gRAoyTkYg4pyU77iPCgpObyBub24ta2V5IGF0dHJpYnV0ZSBjYW4gZGVjaWRlIEEoa2V5KSwgc28gQkNORiDinJTvuI8KCltFdmVudF0KCkV2ZW50SWQ6IHNpbmdsZSB2YWx1ZWQKRXZlbnREYXRlOiBzaW5nbGUgdmFsdWVkCkFkZHJlc3M6IHNpbmdsZSB2YWx1ZWQKQ2l0eTogc2luZ2xlIHZhbHVlZApTdGF0ZTogc2luZ2xlIHZhbHVlZApEZXRhaWw6IHNpbmdsZSB2YWx1ZWQKMU5GIOKclO+4jwoKKGtleSlBOiBFdmVudElkCihub24ta2V5KUI6IEV2ZW50RGF0ZQoobm9uLWtleSlDOiBBZGRyZXNzCihub24ta2V5KUQ6IENpdHkKKG5vbi1rZXkpRTogU3RhdGUKKG5vbi1rZXkpRjogRGV0YWlsCgpBIC0+IEIKQSAtPiBDCkEgLT4gRApBIC0+IEUKQSAtPiBGCjJORiDinJTvuI8KCk5vIG5vbi1rZXkgYXR0cmlidXRlIGNhbiBkZWNpZGUgQShrZXkpLCBzbyBCQ05GIOKclO+4jwoKW1N1cHBvcnRpdmVTZXJ2aWNlc10KClN1cHBvcnRpdmVTZXJ2aWNlc0lkOiBzaW5nbGUgdmFsdWVkClRpdGxlOiBzaW5nbGUgdmFsdWVkClBlcnNvbklkOiBzaW5nbGUgdmFsdWVkCjFORiDinJTvuI8KCihrZXkpQTogU3VwcG9ydGl2ZVNlcnZpY2VzSWQKKG5vbi1rZXkpQjogVGl0bGUKKG5vbi1rZXkpQzogUGVyc29uSWQKCkEgLT4gQgpBIC0+IEMKMk5GIOKclO+4jwoKTm8gbm9uLWtleSBhdHRyaWJ1dGUgY2FuIGRlY2lkZSBBKGtleSksIHNvIEJDTkYg4pyU77iPCgpbTm90aWZpY2F0aW9uXQoKTm90aWZpY2F0aW9uSWQ6IHNpbmdsZSB2YWx1ZWQKUGVyc29uSWQ6IHNpbmdsZSB2YWx1ZWQKTm90aWZpY2F0aW9uVHlwZTogc2luZ2xlIHZhbHVlZApOb3RpZmljYXRpb25EYXRlOiBzaW5nbGUgdmFsdWVkCkRldGFpbDogc2luZ2xlIHZhbHVlZAoxTkYg4pyU77iPCgooa2V5KUE6IE5vdGlmaWNhdGlvbklkCihub24ta2V5KUI6IFBlcnNvbklkCihub24ta2V5KUM6IE5vdGlmaWNhdGlvblR5cGUKKG5vbi1rZXkpRDogTm90aWZpY2F0aW9uRGF0ZQoobm9uLWtleSlFOiBEZXRhaWwKCkEgLT4gQgpBIC0+IEMKQSAtPiBECkEgLT4gRQoyTkYg4pyU77iPCgpObyBub24ta2V5IGF0dHJpYnV0ZSBjYW4gZGVjaWRlIEEoa2V5KSwgc28gQkNORiDinJTvuI8KYGBgCgo1LiAoMjAgcHRzIC8gMS41IGhycykgQ3JlYXRlIGEgc2V0IG9mIFNRTCBkYXRhIGRlZmluaXRpb24gc3RhdGVtZW50cywgcmVhbGl6ZSB0aGF0IHNjaGVtYSBpbiBNeVNRTCBieSBleGVjdXRpbmcgdGhlIHNjcmlwdCBmcm9tIHRoZSBNeVNRTCBjb25zb2xlLgpgYGBzcWwKQ1JFQVRFIFRBQkxFIEhvc3BpdGFsICgKICBIb3NwaXRhbElkIElOVCBOT1QgTlVMTCwKICBOYW1lIFZBUkNIQVIoNDUpLAogIEFkZHJlc3MgVkFSQ0hBUig0NSksCiAgUGhvbmUgVkFSQ0hBUigyMCksCiAgUFJJTUFSWSBLRVkgKEhvc3BpdGFsSWQpCikKQ09NTUVOVCA9ICdIZWFsdGggY2VudGVyIGZvciBjb25uZWN0aW5nIHdpdGggcGF0aWVudHMgYW5kIGNvbnRhY3RzLic7CgoKQ1JFQVRFIFRBQkxFIE1lZGljYWxQcm92aWRlciAoCiAgTWVkaWNhbFByb3ZpZGVySWQgSU5UIE5PVCBOVUxMLAogIFRpdGxlIFZBUkNIQVIoMjApLAogIEZpcnN0TmFtZSBWQVJDSEFSKDIwKSwKICBMYXN0TmFtZSBWQVJDSEFSKDIwKSwKICBIb3NwaXRhbElkIElOVCBOT1QgTlVMTCwKICBQUklNQVJZIEtFWSAoTWVkaWNhbFByb3ZpZGVySWQpLAogIEZPUkVJR04gS0VZIChIb3NwaXRhbElkKQogICAgUkVGRVJFTkNFUyBIb3NwaXRhbChIb3NwaXRhbElkKQopCkNPTU1FTlQgPSAnRG9jdG9yIHdobyBkaWFnbm9zaXMgcGF0aWVudHMuJzsKCgpDUkVBVEUgVEFCTEUgRW1wbG95ZWUgKAogIEVtcGxveWVlSWQgSU5UIE5PVCBOVUxMLAogIEZpcnN0TmFtZSBWQVJDSEFSKDIwKSwKICBMYXN0TmFtZSBWQVJDSEFSKDIwKSwKICBQaG9uZSBJTlQsCiAgUFJJTUFSWSBLRVkgKEVtcGxveWVlSWQpCikKQ09NTUVOVCA9ICdFbXBsb3llZSBmcm9tIGhlYWx0aCBkZXBhcnRtZW50IHdobyBpcyByZXNwb25zaWJsZSBmb3IgY29udGFjdGluZyBwYXRpZW50cyBhbmQgY29udGFjdC4nOwoKCkNSRUFURSBUQUJMRSBQZXJzb24gKAogIFBlcnNvbklkIElOVCBOT1QgTlVMTCwKICBNZWRpY2FsUHJvdmlkZXJJZCBJTlQsCiAgRW1wbG95ZWVJZCBJTlQgTk9UIE5VTEwsCiAgRmlyc3ROYW1lIFZBUkNIQVIoMjApLAogIExhc3ROYW1lIFZBUkNIQVIoMjApLAogIERPQiBEQVRFLAogIEdlbmRlciBFTlVNKCdtYWxlJywgJ2ZlbWFsZScpLAogIEFkZHJlc3MgVkFSQ0hBUig0NSksCiAgQ2l0eSBWQVJDSEFSKDQ1KSwKICBTdGF0ZSBWQVJDSEFSKDQ1KSwKICBQaG9uZSBWQVJDSEFSKDQ1KSwKICBFbWFpbCBWQVJDSEFSKDQ1KSwKICBTTVMgVkFSQ0hBUig0NSksCiAgRGF0ZU9mU3RhcnRRdWFyYW50aW5lIERBVEUsCiAgU291cmNlT2ZJbmZlY3Rpb24gVkFSQ0hBUig0NSksCiAgUmlza0xldmVsIElOVCwKICBQUklNQVJZIEtFWSAoUGVyc29uSWQpLAogIEZPUkVJR04gS0VZIChNZWRpY2FsUHJvdmlkZXJJZCkKICAgIFJFRkVSRU5DRVMgTWVkaWNhbFByb3ZpZGVyKE1lZGljYWxQcm92aWRlcklkKSwKICBGT1JFSUdOIEtFWSAoRW1wbG95ZWVJZCkKICAgIFJFRkVSRU5DRVMgRW1wbG95ZWUoRW1wbG95ZWVJZCkKKQpDT01NRU5UID0gJ0VpdGhlciBhIHRlc3QgcG9zaXRpdmUgcGF0aWVudCBvciBhIHBvdGllbnRpYWwgcGF0aWVudCB3aG8gY29udGFjdHMgd2l0aCBhIHBhdGllbnQnOwoKCkNSRUFURSBUQUJMRSBOb3RpZmljYXRpb24gKAogIE5vdGlmaWNhdGlvbklkIElOVCBOT1QgTlVMTCwKICBQZXJzb25JZCBJTlQgTk9UIE5VTEwsCiAgTm90aWZpY2F0aW9uVHlwZSBWQVJDSEFSKDQ1KSwKICBOb3RpZmljYXRpb25EYXRlIERBVEUsCiAgRGV0YWlsIFZBUkNIQVIoNDUpLAogIFBSSU1BUlkgS0VZIChOb3RpZmljYXRpb25JZCksCiAgRk9SRUlHTiBLRVkgKFBlcnNvbklkKQogICAgUkVGRVJFTkNFUyBQZXJzb24gKFBlcnNvbklkKQopCkNPTU1FTlQgPSAnQm90aCBwYXRpZW50cyBhbmQgY29udGFjdHMgd2lsbCByZWNlaXZlIG5vdGlmaWNhdGlvbiBiYXNlZCBvbiB0aGVpciBoZWFsdGggY29uZGl0aW9uLic7CgoKQ1JFQVRFIFRBQkxFIEV2ZW50ICgKICBFdmVudElkIElOVCBOT1QgTlVMTCwKICBFdmVudERhdGUgREFURSwKICBBZGRyZXNzIFZBUkNIQVIoNDUpLAogIENpdHkgVkFSQ0hBUig0NSksCiAgU3RhdGUgVkFSQ0hBUig0NSksCiAgRGV0YWlsIFZBUkNIQVIoNDUpLAogIFBSSU1BUlkgS0VZIChFdmVudElkKQopCkNPTU1FTlQgPSAnVGhlIGV2ZW50IHRoYXQgcGF0aWVudHMgYW5kIGNvbnRhY3RzIGF0dGVuZC4nOwoKCkNSRUFURSBUQUJMRSBQZXJzb25FdmVudCAoCiAgUGVyc29uSWQgSU5UIE5PVCBOVUxMLAogIEV2ZW50SWQgSU5UIE5PVCBOVUxMLAogIFBSSU1BUlkgS0VZIChQZXJzb25JZCwgRXZlbnRJZCksCiAgRk9SRUlHTiBLRVkgKFBlcnNvbklkKQogICAgUkVGRVJFTkNFUyBQZXJzb24oUGVyc29uSWQpLAogIEZPUkVJR04gS0VZIChFdmVudElkKQogICAgUkVGRVJFTkNFUyBFdmVudChFdmVudElkKQopOwoKCkNSRUFURSBUQUJMRSBTdXBwb3J0aXZlU2VydmljZXMgKAogIFN1cHBvcnRpdmVTZXJ2aWNlc0lkIElOVCBOT1QgTlVMTCwKICBUaXRsZSBWQVJDSEFSKDQ1KSwKICBQUklNQVJZIEtFWSAoU3VwcG9ydGl2ZVNlcnZpY2VzSWQpCikKQ09NTUVOVCA9ICdCb3RoIHBhdGllbnRzIGFuZCBjb250YWN0cyB3aWxsIGdldCBzdXBwb3J0IHNlcnZpY2VzIGR1cmluZyB0aGVpciBxdWFyYW50aW5lIGlmIHRoZXkgZmFjZSBhbnkgaW5jb252ZW5pZW5jZS4nOwoKCkNSRUFURSBUQUJMRSBTZXJ2aWNlc1BlcnNvbiAoCiAgU3VwcG9ydGl2ZVNlcnZpY2VzSWQgSU5UIE5PVCBOVUxMLAogIFBlcnNvbklkIElOVCBOT1QgTlVMTCwKICBQUklNQVJZIEtFWSAoU3VwcG9ydGl2ZVNlcnZpY2VzSWQsIFBlcnNvbklkKSwKICBGT1JFSUdOIEtFWSAoU3VwcG9ydGl2ZVNlcnZpY2VzSWQpCiAgICBSRUZFUkVOQ0VTIFN1cHBvcnRpdmVTZXJ2aWNlcyhTdXBwb3J0aXZlU2VydmljZXNJZCksCiAgRk9SRUlHTiBLRVkgKFBlcnNvbklkKQogICAgUkVGRVJFTkNFUyBQZXJzb24oUGVyc29uSWQpCik7CgoKQ1JFQVRFIFRBQkxFIFNlbGZSZXBvcnQgKAogIFJlcG9ydElkIElOVCBOT1QgTlVMTCwKICBQZXJzb25JZCBJTlQgTk9UIE5VTEwsCiAgUmVwb3J0RGF0ZSBEQVRFLAogIFRlbXBlcmF0dXJlIElOVCwKICBQcm90ZWN0aXZlQmVoYXZpb3IgVkFSQ0hBUig0NSksCiAgUXVhcmFudGluZWQgVElOWUlOVCwKICBQUklNQVJZIEtFWSAoUmVwb3J0SWQpLAogIEZPUkVJR04gS0VZIChQZXJzb25JZCkKICAgIFJFRkVSRU5DRVMgUGVyc29uKFBlcnNvbklkKQopCkNPTU1FTlQgPSAnRGFpbHkgZGF0YSByZXBvcnQgc3VjaCBhcyB0ZW1wZXJhdHVyZSBkYXRhLCBjb250YWN0IGRhdGEuJzsKCgpDUkVBVEUgVEFCTEUgVGVzdFJlc3VsdCAoCiAgVGVzdFJlc3VsdElkIElOVCBOT1QgTlVMTCwKICBSZXBvcnRJZCBJTlQgTk9UIE5VTEwsCiAgRGVzY3JpcHRpb24gVkFSQ0hBUig0NSksCiAgUG9zaXRpdmUgVElOWUlOVCwKICBQUklNQVJZIEtFWSAoVGVzdFJlc3VsdElkKSwKICBGT1JFSUdOIEtFWSAoUmVwb3J0SWQpCiAgICBSRUZFUkVOQ0VTIFNlbGZSZXBvcnQoUmVwb3J0SWQpCikKQ09NTUVOVCA9ICdJZiB0aGUgdGVzdCByZXN1bHQgaXMgcG9zaXRpdmUsIHdoaWNoIG1lYW5zIHRoaXMgcGF0aWVudCAvIGNvbnRhY3RzIGlzIGRpYWdub3NlZCB3aXRoIENvdmlkLTE5Lic7CgoKQ1JFQVRFIFRBQkxFIFN5bXB0b20gKAogIFN5bXB0b21JZCBJTlQgTk9UIE5VTEwsCiAgUmVwb3J0SWQgSU5UIE5PVCBOVUxMLAogIERhdGVPZlN5bXB0b21PbnNldCBEQVRFLAogIFN5bXB0b21EZXRhaWwgVkFSQ0hBUig0NSksCiAgUFJJTUFSWSBLRVkgKFN5bXB0b21JZCksCiAgRk9SRUlHTiBLRVkgKFJlcG9ydElkKQogICAgUkVGRVJFTkNFUyBTZWxmUmVwb3J0KFJlcG9ydElkKQopCkNPTU1FTlQgPSAnU3ltcHRvbSBkZXNjcmlwdGlvbi4nOwoKYGBgCi0gVGFibGUgW0VtcGxveWVlXSBzdWNjZXNzZnVsbHkgY3JlYXRlZCAKCjxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20veWltYW5saXUwL2RhdGFiYXNlL21hc3Rlci9pbWFnZS8xMy5wbmciPgo8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3lpbWFubGl1MC9kYXRhYmFzZS9tYXN0ZXIvaW1hZ2UvMzIucG5nIj4KCi0gVGFibGUgW0V2ZW50XSBzdWNjZXNzZnVsbHkgY3JlYXRlZCAKCjxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20veWltYW5saXUwL2RhdGFiYXNlL21hc3Rlci9pbWFnZS8xMi5wbmciPgo8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3lpbWFubGl1MC9kYXRhYmFzZS9tYXN0ZXIvaW1hZ2UvMzEucG5nIj4KCi0gVGFibGUgW0hvc3BpdGFsXSBzdWNjZXNzZnVsbHkgY3JlYXRlZCAKCjxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20veWltYW5saXUwL2RhdGFiYXNlL21hc3Rlci9pbWFnZS8xMS5wbmciPgo8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3lpbWFubGl1MC9kYXRhYmFzZS9tYXN0ZXIvaW1hZ2UvMzAucG5nIj4KCi0gVGFibGUgW01lZGljYWxQcm92aWRlcl0gc3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgCgo8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3lpbWFubGl1MC9kYXRhYmFzZS9tYXN0ZXIvaW1hZ2UvMTAucG5nIj4KPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzI5LnBuZyI+CgotIFRhYmxlIFtOb3RpZmljYXRpb25dIHN1Y2Nlc3NmdWxseSBjcmVhdGVkIAoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzkucG5nIj4KPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzI4LnBuZyI+CgotIFRhYmxlIFtQZXJzb25dIHN1Y2Nlc3NmdWxseSBjcmVhdGVkIAoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzgucG5nIj4KPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzI3LnBuZyI+CgotIFRhYmxlIFtQZXJzb25FdmVudF0gc3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgCgo8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3lpbWFubGl1MC9kYXRhYmFzZS9tYXN0ZXIvaW1hZ2UvNy5wbmciPgo8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3lpbWFubGl1MC9kYXRhYmFzZS9tYXN0ZXIvaW1hZ2UvMjYucG5nIj4KCi0gVGFibGUgW1NlbGZSZXBvcnRdIHN1Y2Nlc3NmdWxseSBjcmVhdGVkIAoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzYucG5nIj4KPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzI1LnBuZyI+CgotIFRhYmxlIFtTZXJ2aWNlc1BlcnNvbl0gc3VjY2Vzc2Z1bGx5IGNyZWF0ZWQKCjxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20veWltYW5saXUwL2RhdGFiYXNlL21hc3Rlci9pbWFnZS81LnBuZyI+CjxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20veWltYW5saXUwL2RhdGFiYXNlL21hc3Rlci9pbWFnZS8yNC5wbmciPgoKLSBUYWJsZSBbU3VwcG9ydGl2ZVNlcnZpY2VzXSBzdWNjZXNzZnVsbHkgY3JlYXRlZAoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzQucG5nIj4KPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzIzLnBuZyI+CgotIFRhYmxlIFtTeW1wdG9tXSBzdWNjZXNzZnVsbHkgY3JlYXRlZAoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzMucG5nIj4KPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzIyLnBuZyI+CgotIFRhYmxlIFtUZXN0UmVzdWx0XSBzdWNjZXNzZnVsbHkgY3JlYXRlZAoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzIucG5nIj4KPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlLzIxLnBuZyI+Cgo2LiAoMjAgcHRzIC8gMiBocnMpIFdvcmsgYXMgYSBncm91cCB0byBwb3B1bGF0ZSB0aGUgdGFibGVzIHdpdGggdGVzdCBkYXRhLgoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlL0VtcGxveWVlLnBuZyI+Cgo8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3lpbWFubGl1MC9kYXRhYmFzZS9tYXN0ZXIvaW1hZ2UvSG9zcGl0YWwucG5nIj4KCjxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20veWltYW5saXUwL2RhdGFiYXNlL21hc3Rlci9pbWFnZS9NZWRpY2FsUHJvdmlkZXIucG5nIj4KCjxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20veWltYW5saXUwL2RhdGFiYXNlL21hc3Rlci9pbWFnZS9TZWxmUmVwb3J0LnBuZyI+Cgo8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3lpbWFubGl1MC9kYXRhYmFzZS9tYXN0ZXIvaW1hZ2UvU3ltcHRvbS5wbmciPgoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW1hbmxpdTAvZGF0YWJhc2UvbWFzdGVyL2ltYWdlL1Rlc3RSZXN1bHQucG5nIj4KCjxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vU2ltaW4tWmhhbmcvRGF0YWJhc2UvbWFpbi9FdmVudFRlc3QucG5nIj4KCjxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vU2ltaW4tWmhhbmcvRGF0YWJhc2UvbWFpbi9Ob3RpZmljYXRpb25UZXN0LnBuZyI+Cgo8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1NpbWluLVpoYW5nL0RhdGFiYXNlL21haW4vUGVyc29uRXZlbnRUZXN0LnBuZyI+Cgo8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1NpbWluLVpoYW5nL0RhdGFiYXNlL21haW4vUGVyc29uVGVzdC5wbmciPgoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9TaW1pbi1aaGFuZy9EYXRhYmFzZS9tYWluL1NlcnZpY2VzUGVyc29uVGVzdC5wbmciPgoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9TaW1pbi1aaGFuZy9EYXRhYmFzZS9tYWluL1N1cHBvcnRpdmVTZXJ2aWNlc1Rlc3QucG5nIj4KCgo3LiAoMjAgcHRzIC8gMSBocnMpIERlZmluZSBhbmQgZXhlY3V0ZSBhdCBsZWFzdCBmaXZlIHF1ZXJpZXMgdGhhdCBkZW1vbnN0cmF0ZSB0aGF0IHlvdXIgZGF0YWJhc2UgaXMgd29ya2luZy4KCmBgYHNxbAotLSBRdWVyeSAxOiBmaW5kIHRoZSBuYW1lcyBhbmQgYWRkcmVzc2VzIG9mIGhvc3BpdGFsIHdoaWNoIGhhdmUgbW9yZSB0aGFuIDUgcGVyc29uIGFuZCBob3cgbXVjaCBwZXJzb25zIHRoZXkgaGF2ZS4KLS0gYSBqb2luIG9mIGF0IGxlYXN0IHRocmVlIHRhYmxlcwotLSBhIGdyb3VwIGJ5IHdpdGggYSBoYXZpbmcgY2xhdXNlClNFTEVDVAogIGguTmFtZSwKICBoLkFkZHJlc3MsCiAgQ09VTlQocC5QZXJzb25JZCkgcGVyc29uQ291bnQKRlJPTSBIb3NwaXRhbCBoCkpPSU4gTWVkaWNhbFByb3ZpZGVyIG0KT04gbS5Ib3NwaXRhbElkPWguSG9zcGl0YWxJZApKT0lOIFBlcnNvbiBwCk9OIHAuTWVkaWNhbFByb3ZpZGVySWQ9bS5NZWRpY2FsUHJvdmlkZXJJZApHUk9VUCBCWSBoLm5hbWUKSEFWSU5HIHBlcnNvbkNvdW50PjU7CgoKCgotLSBRdWVyeSAyOiBmaW5kIHRoZSBudW1iZXJzIG9mIG1hbGUgYW5kIGZlbWFsZSBwZXJzb25zLgotLSBhbiBhZHZhbmNlZCBxdWVyeSBtZWNoYW5pc21zIFNFTEVDVCBDQVNFL1dIRU4KU0VMRUNUCiAgU1VNKENBU0UgV0hFTiBHZW5kZXI9J21hbGUnIFRIRU4gMSBFTFNFIDAgRU5EKSBtYWxlQ291bnQsCiAgU1VNKENBU0UgV0hFTiBHZW5kZXI9J2ZlbWFsZScgVEhFTiAxIEVMU0UgMCBFTkQpIGZlbWFsZUNvdW50CkZST00gUGVyc29uOwoKCgotLSBRdWVyeSAzOiBmaW5kIHRoZSByZXBvcnRzIHN0YXJ0aW5nIGZyb20gQXByaWwgMjAyMCB3aGljaCBoYXZlIHN5bXB0b20gYnV0IHRlc3QgbmVnYXRpdmUsIG9yZGVyaW5nIGJ5IGxhdGVzdCBkYXRlCi0tIGEgc3VicXVlcnkKLS0gYSBjb21wbGV4IHNlYXJjaCBjcml0ZXJpb24gdXNpbmcgQU5EClNFTEVDVCAqCkZST00gU2VsZlJlcG9ydCByCldIRVJFIHIuUmVwb3J0RGF0ZSA+PSAnMjAyMC0wNC0wMScKQU5EIEVYSVNUUyAoU0VMRUNUIDEgRlJPTSBTeW1wdG9tIHMgV0hFUkUgcy5SZXBvcnRJZD1yLlJlcG9ydElkKQpBTkQgci5SZXBvcnRJZCBOT1QgSU4gKFNFTEVDVCBSZXBvcnRJZCBGUk9NIFRlc3RSZXN1bHQgV0hFUkUgUG9zaXRpdmU9VHJ1ZSkKT1JERVIgQlkgci5SZXBvcnREYXRlIERFU0M7CgoKCgoKLS0gUXVlcnkgNDogZmluZCB0aGUgYWdlIHJhbmdlIGRpc3RyaWJ1dGlvbiBvZiBwZXJzb25zLgotLSBhbiBhZHZhbmNlZCBxdWVyeSBtZWNoYW5pc21zIFNFTEVDVCBDQVNFL1dIRU4KU0VMRUNUIAogIENBU0UgV0hFTiAoREFURV9GT1JNQVQoTk9XKCksICclWScpIC0gREFURV9GT1JNQVQoRE9CLCAnJVknKSAtIChEQVRFX0ZPUk1BVChOT1coKSwgJzAwLSVtLSVkJykgPCBEQVRFX0ZPUk1BVChET0IsICcwMC0lbS0lZCcpKSkgPCAyMCBUSEVOICc8MjAnCiAgICAgV0hFTiAoREFURV9GT1JNQVQoTk9XKCksICclWScpIC0gREFURV9GT1JNQVQoRE9CLCAnJVknKSAtIChEQVRFX0ZPUk1BVChOT1coKSwgJzAwLSVtLSVkJykgPCBEQVRFX0ZPUk1BVChET0IsICcwMC0lbS0lZCcpKSkgPCAzMCBUSEVOICcyMC0yOScKICAgICBXSEVOIChEQVRFX0ZPUk1BVChOT1coKSwgJyVZJykgLSBEQVRFX0ZPUk1BVChET0IsICclWScpIC0gKERBVEVfRk9STUFUKE5PVygpLCAnMDAtJW0tJWQnKSA8IERBVEVfRk9STUFUKERPQiwgJzAwLSVtLSVkJykpKSA8IDQwIFRIRU4gJzMwLTM5JwogICAgIFdIRU4gKERBVEVfRk9STUFUKE5PVygpLCAnJVknKSAtIERBVEVfRk9STUFUKERPQiwgJyVZJykgLSAoREFURV9GT1JNQVQoTk9XKCksICcwMC0lbS0lZCcpIDwgREFURV9GT1JNQVQoRE9CLCAnMDAtJW0tJWQnKSkpIDwgNTAgVEhFTiAnNDAtNDknCiAgICAgV0hFTiAoREFURV9GT1JNQVQoTk9XKCksICclWScpIC0gREFURV9GT1JNQVQoRE9CLCAnJVknKSAtIChEQVRFX0ZPUk1BVChOT1coKSwgJzAwLSVtLSVkJykgPCBEQVRFX0ZPUk1BVChET0IsICcwMC0lbS0lZCcpKSkgPCA2MCBUSEVOICc1MC01OScKICAgICBFTFNFICc+NjAnIEVORCBBUyBhZ2UsCiAgICAgQ09VTlQoUGVyc29uSWQpIHBlcnNvbnMKRlJPTSBQZXJzb24KR1JPVVAgQlkgYWdlCk9SREVSIEJZIEZJRUxEKGFnZSwgJzwyMCcsICcyMC0yOScsICczMC0zOScsICc0MC00OScsICc1MC01OScsICc+NjAnKTsKCgoKCi0tIFF1ZXJ5IDU6RmluZCB0aGUgbmFtZXMgYXR0ZW5kIE11c2ljIGV2ZW50LgotLSBqb2luIG9mIGF0IGxlYXN0IDMgdGFibGVzLgotLSBjb250YWluIGEgY29tcGxleCBzZWFyY2ggY3JpdGVyaW9uIHVzaW5nIExJS0UuClNFTEVDVCBkaXN0aW5jdCBQZXJzb24uRmlyc3ROYW1lLCBQZXJzb24uTGFzdE5hbWUKIEZST00gUGVyc29uCiBKT0lOIFBlcnNvbkV2ZW50IE9OIFBlcnNvbkV2ZW50LlBlcnNvbklkID0gUGVyc29uLlBlcnNvbklkCiBKT0lOIEV2ZW50IE9OIEV2ZW50LkV2ZW50SWQgPSBQZXJzb25FdmVudC5FdmVudElkCiBXSEVSRSBFdmVudC5EZXRhaWwgTElLRSAiJU11c2ljJSI7CgoKLS0gUXVlcnkgNjogRmluZCB0aGUgbnVtYmVyIG9mIE1hbGUgd2hvIHRlc3RzIHBvc2l0aXZlLgotLSBqb2luIG9mIGF0IGxlYXN0IDMgdGFibGVzLgotLSBjb250YWluIGEgY29tcGxleCBzZWFyY2ggY3JpdGVyaW9uIHVzaW5nIEFORC4KU0VMRUNUIENPVU5UKCopIEFTIE51bWJlcgpGUk9NIFBlcnNvbgpKT0lOIFNlbGZSZXBvcnQgT04gU2VsZlJlcG9ydC5QZXJzb25JZCA9IFBlcnNvbi5QZXJzb25JZApKT0lOIFRlc3RSZXN1bHQgT04gVGVzdFJlc3VsdC5SZXBvcnRJZCA9IFNlbGZSZXBvcnQuUmVwb3J0SWQKV0hFUkUgVGVzdFJlc3VsdC5Qb3NpdGl2ZSA9ICdUcnVlJwpBTkQgUGVyc29uLkdlbmRlciA9ICdNYWxlJzsKCgotLSBRdWVyeSA3OiBMaXN0IHRoZSBTZXJ2aWNlIG5hbWUgYW5kIHRoZSBudW1iZXIgb2YgdGhhdCBTZXJ2aWNlLCB3aGljaCBpcyBncmVhdGVyIHRoYW4gMi4gCi0tIGdyb3VwIGJ5IHdpdGggYSBoYXZpbmcgY2xhdXNlClNFTEVDVCBTdXBwb3J0aXZlU2VydmljZXMuVGl0bGUsIENPVU5UKFNlcnZpY2VzUGVyc29uLlN1cHBvcnRpdmVTZXJ2aWNlc0lkKSBBUyBOdW1iZXIKRlJPTSBTZXJ2aWNlc1BlcnNvbgpKT0lOIFN1cHBvcnRpdmVTZXJ2aWNlcyBPTiBTZXJ2aWNlc1BlcnNvbi5TdXBwb3J0aXZlU2VydmljZXNJZCA9IFN1cHBvcnRpdmVTZXJ2aWNlcy5TdXBwb3J0aXZlU2VydmljZXNJZApHUk9VUCBCWSBTZXJ2aWNlc1BlcnNvbi5TdXBwb3J0aXZlU2VydmljZXNJZApIQVZJTkcgTnVtYmVyID4yOwoKCmBgYAoKUXVlcnkgMToKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9TaW1pbi1aaGFuZy9EYXRhYmFzZS9tYWluL1F1ZXJ5MS5wbmciPgoKUXVlcnkgMjoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9TaW1pbi1aaGFuZy9EYXRhYmFzZS9tYWluL1F1ZXJ5Mi5wbmciPgoKUXVlcnkgMzoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9TaW1pbi1aaGFuZy9EYXRhYmFzZS9tYWluL1F1ZXJ5My5wbmciPgoKUXVlcnkgNDoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9TaW1pbi1aaGFuZy9EYXRhYmFzZS9tYWluL1F1ZXJ5NC5wbmciPgoKUXVlcnkgNToKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9TaW1pbi1aaGFuZy9EYXRhYmFzZS9tYWluL1F1ZXJ5NS5wbmciPgoKUXVlcnkgNjoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9TaW1pbi1aaGFuZy9EYXRhYmFzZS9tYWluL1F1ZXJ5Ni5wbmciPgoKUXVlcnkgNzoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9TaW1pbi1aaGFuZy9EYXRhYmFzZS9tYWluL1F1ZXJ5Ny5wbmciPgoKCgoKCmBgYHtSfQojIGxvYWQgbGlicmFyaWVzCmxpYnJhcnkoREJJKQpsaWJyYXJ5KG9kYmMpCmxpYnJhcnkoZ2dwbG90MikKCiMgY29ubmVjdCB0byBteXNxbApjb24gPC0gREJJOjpkYkNvbm5lY3Qob2RiYzo6b2RiYygpLAogICAgICAgICAgICAgICAgICAgICAgRHJpdmVyICAgPSAiTXlTUUwiLAogICAgICAgICAgICAgICAgICAgICAgU2VydmVyICAgPSAiY3M1MjAwLmNlcnVnb2M5cDV1eC51cy1lYXN0LTEucmRzLmFtYXpvbmF3cy5jb20iLAogICAgICAgICAgICAgICAgICAgICAgRGF0YWJhc2UgPSAicHJhY3RpY3VtLWkiLAogICAgICAgICAgICAgICAgICAgICAgVUlEICAgICAgPSAiYWRtaW4iLAogICAgICAgICAgICAgICAgICAgICAgUFdEICAgICAgPSAiY3M1MjAwZGIiLAogICAgICAgICAgICAgICAgICAgICAgUG9ydCAgICAgPSAzMzA2KQoKIyBidWlsZCBxdWVyeQpxdWVyeSA8LSBkYlNlbmRRdWVyeShjb24sICJTRUxFQ1QgCiAgQ0FTRSBXSEVOIChEQVRFX0ZPUk1BVChOT1coKSwgJyVZJykgLSBEQVRFX0ZPUk1BVChET0IsICclWScpIC0gKERBVEVfRk9STUFUKE5PVygpLCAnMDAtJW0tJWQnKSA8IERBVEVfRk9STUFUKERPQiwgJzAwLSVtLSVkJykpKSA8IDIwIFRIRU4gJzwyMCcKICAgICBXSEVOIChEQVRFX0ZPUk1BVChOT1coKSwgJyVZJykgLSBEQVRFX0ZPUk1BVChET0IsICclWScpIC0gKERBVEVfRk9STUFUKE5PVygpLCAnMDAtJW0tJWQnKSA8IERBVEVfRk9STUFUKERPQiwgJzAwLSVtLSVkJykpKSA8IDMwIFRIRU4gJzIwLTI5JwogICAgIFdIRU4gKERBVEVfRk9STUFUKE5PVygpLCAnJVknKSAtIERBVEVfRk9STUFUKERPQiwgJyVZJykgLSAoREFURV9GT1JNQVQoTk9XKCksICcwMC0lbS0lZCcpIDwgREFURV9GT1JNQVQoRE9CLCAnMDAtJW0tJWQnKSkpIDwgNDAgVEhFTiAnMzAtMzknCiAgICAgV0hFTiAoREFURV9GT1JNQVQoTk9XKCksICclWScpIC0gREFURV9GT1JNQVQoRE9CLCAnJVknKSAtIChEQVRFX0ZPUk1BVChOT1coKSwgJzAwLSVtLSVkJykgPCBEQVRFX0ZPUk1BVChET0IsICcwMC0lbS0lZCcpKSkgPCA1MCBUSEVOICc0MC00OScKICAgICBXSEVOIChEQVRFX0ZPUk1BVChOT1coKSwgJyVZJykgLSBEQVRFX0ZPUk1BVChET0IsICclWScpIC0gKERBVEVfRk9STUFUKE5PVygpLCAnMDAtJW0tJWQnKSA8IERBVEVfRk9STUFUKERPQiwgJzAwLSVtLSVkJykpKSA8IDYwIFRIRU4gJzUwLTU5JwogICAgIEVMU0UgJz42MCcgRU5EIEFTIGFnZSwKICAgICBDT1VOVChQZXJzb25JZCkgcGVyc29ucwpGUk9NIFBlcnNvbgpHUk9VUCBCWSBhZ2UKT1JERVIgQlkgRklFTEQoYWdlLCAnPDIwJywgJzIwLTI5JywgJzMwLTM5JywgJzQwLTQ5JywgJzUwLTU5JywgJz42MCcpIikKCiMgZmV0Y2ggZGF0YQpkZiA8LSBkYkZldGNoKHF1ZXJ5KQoKIyBsb2NrIHRoZSBvcmRlcgpkZiRhZ2UgPC0gZmFjdG9yKGRmJGFnZSwgbGV2ZWxzID0gZGYkYWdlKQoKIyBwbG90CmdncGxvdChkZiwgYWVzKHg9YWdlLCB5PXBlcnNvbnMpKSArCiAgZ2VvbV9jb2woZGF0YT1kZikgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHM9YygwLDIwKSkKYGBgCgohW0JhckNoYXJ0X0FnZVJhbmdlRGlzdHJpYnV0aW9uXShodHRwczovL3phY3cucnN0dWRpby5jbG91ZC8wNDY5Y2YyNzJjZjc0MWIxODNjNDBjZjI5MzI2ODZjZi9maWxlX3Nob3c/cGF0aD0lMkZjbG91ZCUyRnByb2plY3QlMkZCYXJDaGFydF9BZ2VSYW5nZURpc3RyaWJ1dGlvbi5wbmcpCgo8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3lpbWFubGl1MC9kYXRhYmFzZS9tYXN0ZXIvaW1hZ2UvY2hhcnQucG5nIj4K